package cn.tx.service.impl;


import cn.tx.result.Result;
import cn.tx.result.ResultUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author: 可乐加糖
 * @create: 2023-02-28 15:16
 * @Description: Redis 实现订单超卖和秒杀
 */
@Service
public class RedisSetNxServiceImpl implements RedisSetNxService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

//    @Resource
//    private RedisSetNxDAO redisSetNxDAO;

    private final static String SUO_KEY = "cs:suo:";

    @Override
    public Result cs(Long uid, Long je) {
        // 获取锁
        boolean huoQu = huoqu(je);
        if (!huoQu) {
            try {
                // 没有获取到 持续获取 也可以直接返回一个状态 让他重新请求
                while (!huoqu(je)){
                    // 没有获取到锁 休眠一段时间在重新获取
                    // 目的是为了和上一个线程的业务代码错开
                    // 避免不必要的cpu消耗
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
                throw new RuntimeException("异常了!!!!!!!");
            }
        }
        // 获取到了锁 执行代码
        try {
            // 业务代码
            // 查询剩余库存
            //Long num = redisSetNxDAO.findKc(je);
            Long num = 12L;
            if (num == null || num < 1) {
                // 库存不足。返回状态
                System.out.println("库存不足！！！！！");
                return ResultUtil.custom(10000,"库存不足！！！！！");
            }
            // 库存足够 减库存
            // 获取当前线程ID
            Long id = Thread.currentThread().getId();

            // 扣减库存
            //redisSetNxDAO.findDele(je);

            // 生成订单 记录基本信息
            //redisSetNxDAO.saveKc(uid, je, Long.valueOf(i));
        } catch (Exception e) {
            throw new RuntimeException("异常了!!!!!!!");
        } finally {
            // 锁释放 释放锁一定要放在 finally 下
            // 防止业务代码报错。导致锁无法释放。造成死锁
            shanc(je);
        }
        return ResultUtil.success();
    }


    /**
     * 获取锁
     *
     * @return
     */
    public boolean huoqu(Long je) {
        String uuid = UUID.randomUUID().toString();
        return Boolean.TRUE.equals(stringRedisTemplate.opsForValue().setIfAbsent(SUO_KEY + je, uuid,60,TimeUnit.SECONDS));
    }

    /**
     * 释放锁
     *
     * @return
     */
    public void shanc(Long je) {
        stringRedisTemplate.delete(SUO_KEY + je);
    }

}

